package com.hougong.im.transport;

import com.hougong.im.utils.ProtocolUtils;
import com.hougong.im.utils.StringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicInteger;


/**
 * 解码器 将AbstractNetFrame 解码
 * 1. 计算校验码
 * 2. 转义
 * 3.填充首尾标识符
 */
public class ProtocolEncoder extends MessageToByteEncoder<BaseFrame> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ProtocolEncoder.class);
    private static AtomicInteger steamIdGen = new AtomicInteger(0);

    private static int getNextStreamId() {
        if (steamIdGen.get() == Integer.MAX_VALUE) {
            steamIdGen.set(0);
            return 0;
        } else {
            return steamIdGen.getAndIncrement();
        }
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, BaseFrame msg, ByteBuf out) throws Exception {
        out.writeBytes(encode1(msg));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    /**
     * 计算长度，填充校验码 转义 填充起始码
     * @param msg
     * @return
     */
    public static byte[] encode1(BaseFrame msg) {
        preHandle(msg);
//        LOGGER.info("编码前要发送的数据," + msg);
        ByteBuf byteBuf = Unpooled.buffer();

        int streamId = msg.getStreamId();
        byte version = msg.getVersion();
        byte messageType = msg.getMessageType();
        short bizType = msg.getBizType();
        byte[] body = msg.getBody();
        int len = body.length+8;
        byteBuf.writeInt(len)
                .writeInt(streamId)
                .writeByte(version)
                .writeByte(messageType)
                .writeShort(bizType);
        if (body.length > 0) {
            byteBuf.writeBytes(body);
        }
        byte[] bytes = new byte[byteBuf.readableBytes() + 1];
        byteBuf.readBytes(bytes, 0, byteBuf.readableBytes());
        byte check = ProtocolUtils.computeCheck(bytes, 0, bytes.length);
        bytes[bytes.length - 1] = check;
        //转义
        byte[] escape = ProtocolUtils.escape(bytes);
        //首填装标志符
        byte[] resultByteArr = new byte[escape.length + 1];
        System.arraycopy(escape, 0, resultByteArr, 1, escape.length);
        resultByteArr[0] = BaseFrame.START_FLAG;
//        LOGGER.info("编码后发送的数据" + StringUtils.bytesToHexString(resultByteArr));
        return resultByteArr;
    }

    public static void preHandle(BaseFrame msg) {
        byte[] body = msg.getBody();
        msg.setLength(8 + body.length);
        msg.setStreamId(getNextStreamId());
        msg.setVersion(BaseFrame.VERSION);
    }


}
